import 'dart:async';

import 'package:date_format/date_format.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:imperius_insights/entity/project.dart';
import 'package:imperius_insights/events/event-bus.dart';
import 'package:imperius_insights/events/scope-changed-event.dart';
import 'package:imperius_insights/portal/state/indicator/indicator.dart';
import 'package:imperius_insights/portal/state/mobx/store.dart';
import 'package:imperius_insights/portal/toolkits/date.dart';
import 'package:imperius_insights/portal/viewmodel.dart';
import 'package:imperius_insights/modules/projects/viewmodels/project.dart';
import 'package:imperius_insights/treaty/styles.dart';
import 'package:mobx/mobx.dart';
import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:imperius_insights/modules/scope/domain.dart' as Scope;
import 'package:url_launcher/url_launcher.dart';

import 'domain.dart';

part 'view_model.g.dart';

class ViewModel = _ViewModelInternal with _$ViewModel;

abstract class _ViewModelInternal with Store, StoreWithLifecycle {
  CalendarController _calendarController;

  Domain _domain;

  StreamSubscription<ScopeChangedEvent> _scopeChangedSubscriber;

  ScrollController scrollController;

  setScrollController(ScrollController scrollController) {
    this.scrollController = scrollController;
  }

  CalendarController get calendarController => _calendarController;

  @observable
  IndicatorState<List<ProjectViewModel>> projects;

  @observable
  Map<DateTime, List> calendarEvents;

  @observable
  List<ProjectViewModel> markedProjects;

  bool checkAndMakeAlarm;

  @computed
  String get selectedDayTasksTitle {
    if (markedProjects == null) {
      return '';
    }
    final selectedDay = _calendarController.selectedDay;
    String dayPrefix = isSameDay(selectedDay, DateTime.now())
        ? '今日'
        : '${formatDate(selectedDay, [mm, '月', dd, '日'])}';
    if (markedProjects.length == 0) {
      return '$dayPrefix无安排（${formatDate(selectedDay, [
        yyyy,
        '-',
        mm,
        '-',
        dd
      ])}）';
    }
    return '$dayPrefix有${markedProjects.length}个项目需要关注';
  }

  _ViewModelInternal({ this.checkAndMakeAlarm = true }) {
    _domain = Domain();
  }

  onTodoProjectTaped(ProjectViewModel project) {
    launch(project.jiraLink);
  }

  @override
  onContextAttached(BuildContext context) {
    super.onContextAttached(context);
    _calendarController = CalendarController();
    projects = IndicatorState<List<ProjectViewModel>>();
    _scopeChangedSubscriber =
        defaultEventBus.on<ScopeChangedEvent>().listen((_) => this.refresh());
    refresh();
  }

  @override
  onContextDetached(BuildContext context) {
    _calendarController.dispose();
    super.onContextDetached(context);
    _scopeChangedSubscriber.cancel();
  }

  @action
  onSelectCalendarDay(DateTime day, List events) {
    if (projects.status != Status.completed) {
      this.markedProjects = [];
      return;
    }
    this.markedProjects = projects.data.where((p) {
      final expectLaterStaging = p.calcMilestoneStaging(day);
      if (expectLaterStaging == Staging.Unset ||
          expectLaterStaging == Staging.Scheduled) {
        return false;
      }
      if (p.data.scheduledPublishDate != null &&
          (expectLaterStaging == Staging.PrePublish ||
              expectLaterStaging == Staging.PostPublish) &&
          !isSameDay(p.data.scheduledPublishDate, day)) {
        return false;
      }
      return true;
    }).toList(growable: false);
  }

  @action
  void onProjectTaped(ProjectViewModel projectVm) {
    final today = DateTime.now();
    final project = projectVm.data;
    if (today.isAfter(project.startDevDate) &&
        (project.scheduledPublishDate != null &&
            today.isBefore(project.scheduledPublishDate))) {
      _calendarController.setFocusedDay(today);
    } else {
      _calendarController.setFocusedDay(project.startDevDate);
    }

    final putEventWorkday = (DateTime date) {
      if (date.weekday == DateTime.saturday || date.weekday == DateTime.sunday) {
        return;
      }
      calendarEvents[date] = [project.pmo];
    };

    calendarEvents = Map<DateTime, List>();
    if (project.startDevDate != null && project.endDevDate != null) {
      for (DateTime cursor = project.startDevDate;
          cursor.isBefore(project.endDevDate) || cursor == project.endDevDate;
          cursor = cursor.add(Duration(days: 1))) {
        putEventWorkday(cursor);
      }
    }

    if (project.startTestDate != null && project.endTestDate != null) {
      for (DateTime cursor = project.startTestDate;
          cursor.isBefore(project.endTestDate) || cursor == project.endTestDate;
          cursor = cursor.add(Duration(days: 1))) {
        putEventWorkday(cursor);
      }
    }

    if (project.scheduledPublishDate != null) {
      putEventWorkday(project.scheduledPublishDate);
    }
  }

  ProjectViewModel queryByPMO(String pmo) {
    try {
      return projects.data.firstWhere((p) => p.data.pmo == pmo);
    } catch (err) {
      print('could not query the pmo of $pmo');
      throw err;
    }
  }

  Future<void> refresh() async {
    try {
      final scopeDomain = Provider.of<Scope.Domain>(context, listen: false);
      final departmentId = await scopeDomain.getDepartmentId();
      final scopeHumanId = await scopeDomain.getScopeHumanId();
      final department = scopeDomain.queryDepartment(departmentId: departmentId);
      projects.fireFetch(() async {
        List<Project> projects;
        if (department.combinedDepartments == null) {
          projects = await _domain.load(
              departmentId: departmentId, scopeHumanId: scopeHumanId);  
        } else {
          projects = await _domain.loadMulti(
              departmentIds: department.combinedDepartments.map((e) => e.id).toList(), scopeHumanId: scopeHumanId);
        }
        if (scopeHumanId != null) {
          projects = projects.where((p) {
            return p.humansOfRD.indexWhere((h) => h.sysName == scopeHumanId) >=
                    0 ||
                p.humansOfQA.indexWhere((h) => h.sysName == scopeHumanId) >= 0;
          }).toList(growable: true);
        }
        runInAction(() => calendarEvents = Map<DateTime, List>());
        return arraysTo(projects, (p) => ProjectViewModel(p));
      }).then((_) {
        onSelectCalendarDay(_calendarController.selectedDay, []);
        if (checkAndMakeAlarm) {
          _checkAndMakeAlarm();
        }
      });
    } catch (err) {
      print(err);
    }
  }

  FutureOr<dynamic> _checkAndMakeAlarm() {
    if (this.projects.data == null || this.projects.data.length == 0) {
      return 0;
    }
    final delayProjects = this.projects.data.where((p) => p.delay != null);
    if (delayProjects.length == 0) {
      return 0;
    }
    String delayNamesText = delayProjects.map((p) => p.name).join('\n');
    showDialog<bool>(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text('⚠️以下项目PMO状态为Delay️', style: styles.content),
          content: Text('$delayNamesText', style: styles.contentTip),
          actions: <Widget>[
            FlatButton(
              child: Text("去项目管理视图看详情"),
              onPressed: () => Navigator.of(context).pop(), // 关闭对话框
            ),
          ],
        );
      },
    );
  }
}
